package srv

import (
	"arc_srv4/common"
	apiUtil "arc_srv4/face/__4_0"
	"arc_srv4/logutils"
	"arc_srv4/utils"
	"encoding/base64"
	"github.com/kataras/iris/v12"
	"go.uber.org/zap"
)

var (
	RedisFaceCheck = "face_transId_check"
	RedisFaceBind  = "face_transId_bind"
)

// post 处理人脸数据并返回
func CheckFace(ctx iris.Context) {
	req := new(common.FaceCheckReq)
	if err := ctx.ReadJSON(&req); err != nil {
		// 参数错误
		_, _ = ctx.JSON(common.ApiNoDataResponse(common.Http10006, common.Http10006Desc))
	} else {
		if req.DeviceNo == "" {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "尚未读取到设备信息"))
			return
		}

		transId := req.TransId
		if !common.AppConCfg.Repeat {
			tranIdRedis := string(utils.RedisGet(RedisFaceCheck))
			if tranIdRedis == transId {
				_, _ = ctx.JSON(common.ApiNoDataResponse(500, "该请求已经处理，无需重复请求"))
				return
			}
		}

		imageByte, message := apiUtil.ImageByte(req.Faces, transId)
		if imageByte == nil {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, message))
			return
		}

		ib, message := apiUtil.SaveImage(common.AppConCfg.Path.Check, "face_"+transId+".jpg", imageByte, transId)
		if !ib {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, message))
			return
		}

		if !apiUtil.ActivationClient(common.ArcCfg.AppId, common.ArcCfg.AppKey, common.ArcCfg.ActiveKey) {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "激活失败"))
			return
		}
		width, height, imageData := apiUtil.ImageConvert(imageByte, transId)

		ic, engine := apiUtil.InitEngineUtil(transId)
		if !ic {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "初始化引擎失败"))
			return
		}

		ibr := apiUtil.SetLiveUtil(engine, transId, common.AppConCfg.Face.Thresholdmodel_BGR, common.AppConCfg.Face.Thresholdmodel_IR)
		if !ibr {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "设置活体可信度失败"))
			return
		}

		icr := apiUtil.SetShelterUtil(engine, transId, common.AppConCfg.Face.Thresholdmodel_Mask)
		if !icr {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "设置面部遮挡失败"))
			return
		}

		info := apiUtil.DectFaceUtil(engine, transId, width, height, imageData)
		if info == nil {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "检测人脸失败"))
			return
		}

		if info.FaceNum == 0 {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "未检测到人脸"))
			return
		}

		lp := new(common.FaceData)
		//提取特征码
		if info.FaceNum > 0 {
			single := apiUtil.NewSingleFace(info)

			ix, features := apiUtil.FeatureExtractUtil(engine, transId, width, height, imageData, single, 0, 1)
			if !ix {
				_, _ = ctx.JSON(common.ApiNoDataResponse(500, "提取比对人 人脸特征值失败"))
				return
			}

			res := utils.QueryFacesFromRedis()
			if res == nil {
				_, _ = ctx.JSON(common.ApiNoDataResponse(500, "查无人脸数据"))
				return
			}

			checkSuccess := false
			// 比对人脸特征 （数据库只存人脸图片，通过人脸图片提取特征码循环比对）
			for _, v := range res {
				ff, _ := base64.StdEncoding.DecodeString(v.Photo)
				feaRes := apiUtil.ConvertToFaceFeaturePro(ff)
				result := apiUtil.CompareFaceUtil(engine, transId, features, feaRes, 0)
				if result < 0 {
					_, _ = ctx.JSON(common.ApiNoDataResponse(500, "比对人 人脸特征值失败"))
					continue
				}

				if result > 0.9 && result <= 1 {
					lp.ReaderId = v.ReaderId
					lp.ReaderName = v.ReaderName
					lp.ModifyTime = v.ModifyTime
					lp.Valid = v.Valid
					checkSuccess = true

					// 正式上线后需要 打开注释 如果匹配则学习
					faceData := base64.StdEncoding.EncodeToString(features.Feature)
					iba := apiUtil.AddNeWFace(v.ReaderId, faceData, req.Faces, transId)
					if !iba {
						_, _ = ctx.JSON(common.ApiNoDataResponse(500, "学习人脸失败"))
						return
					}
					// 释放人脸特征所占内存
					apiUtil.ReleaseFeature(features)
					apiUtil.ReleaseFeature(feaRes)
					break
				}

				apiUtil.ReleaseFeature(feaRes)
			}

			if !checkSuccess {
				apiUtil.ReleaseEngine(engine, req.TransId)
				logutils.Logger.Info("未比对出人脸数据.", zap.String("transId", req.TransId))
				_, _ = ctx.JSON(common.ApiNoDataResponse(500, "未比对出人脸数据"))
				return
			}
		} else {
			apiUtil.ReleaseEngine(engine, req.TransId)
			logutils.Logger.Info("未发现人脸数据.", zap.String("transId", req.TransId))
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "未发现人脸数据"))
			return
		}

		apiUtil.ReleaseEngine(engine, transId)
		if !common.AppConCfg.Repeat {
			utils.RedisSet(RedisFaceCheck, req.TransId, -1)
		}
		_, _ = ctx.JSON(common.ApiResponse(200, lp, "success"))
		return
	}
}

func BindFace(ctx iris.Context) {
	req := new(common.BindFaceReq)
	if err := ctx.ReadJSON(&req); err != nil {
		// 参数错误
		_, _ = ctx.JSON(common.ApiNoDataResponse(common.Http10006, common.Http10006Desc))
	} else {
		if req.ReaderId == "" {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "尚未读取到读者信息"))
			return
		}

		transId := req.TransId
		if !common.AppConCfg.Repeat {
			tranIdRedis := string(utils.RedisGet(RedisFaceBind))
			if tranIdRedis == transId {
				_, _ = ctx.JSON(common.ApiNoDataResponse(500, "该请求已经处理，无需重复请求"))
				return
			}
			utils.RedisSet(RedisFaceBind, req.TransId, -1)
		}

		imageByte, message := apiUtil.ImageByte(req.Faces, transId)
		if imageByte == nil {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, message))
			return
		}

		ib, message := apiUtil.SaveImage(common.AppConCfg.Path.Bind, "face_"+transId+".jpg", imageByte, transId)
		if !ib {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, message))
			return
		}

		if !apiUtil.ActivationClient(common.ArcCfg.AppId, common.ArcCfg.AppKey, common.ArcCfg.ActiveKey) {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "激活失败"))
			return
		}
		width, height, imageData := apiUtil.ImageConvert(imageByte, transId)

		ic, engine := apiUtil.InitEngineUtil(transId)
		if !ic {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "初始化引擎失败"))
			return
		}

		info := apiUtil.DectFaceUtil(engine, transId, width, height, imageData)
		if info == nil {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "检测人脸失败"))
			return
		}

		if info.FaceNum <= 0 {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "未检测到人脸"))
			return
		}

		single := apiUtil.NewSingleFace(info)
		ib, ff := apiUtil.FeatureExtractUtil(engine, transId, width, height, imageData, single, 0, 0)
		if !ib {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "提取单个人脸特征值失败"))
			return
		}
		apiUtil.ReleaseEngine(engine, transId)

		faceData := base64.StdEncoding.EncodeToString(ff.Feature)
		iba := apiUtil.AddNeWFace(req.ReaderId, faceData, req.Faces, transId)
		if !iba {
			_, _ = ctx.JSON(common.ApiNoDataResponse(500, "绑定人脸失败"))
			return
		}
		_, _ = ctx.JSON(common.ApiNoDataResponse(200, "绑定成功"))
		return
	}
}
